#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <string>
#include <stdio.h>
#include <cassert>
#include <iostream>
#include "Base64.cpp"
using namespace std;

int EncodeRSAKeyFile(const char * _strPemFileName,const char * _strData,unsigned char* buffer,int length){
	string strPemFileName=_strPemFileName;
	string strData=_strData;
	if(strPemFileName.empty() || strData.empty()){
		assert(false);
		return 0;
	}
	FILE *hPubKeyFile =fopen(strPemFileName.c_str(),"rb");
	if(hPubKeyFile==NULL){
		assert(false);
		return 0;
	}
	std::string strRet;
	RSA * pRSAPublicKey = RSA_new();
	if(PEM_read_RSA_PUBKEY(hPubKeyFile , &pRSAPublicKey , 0 , 0) == NULL){
		assert(false);
		return 0;
	}
	int nLen = RSA_size(pRSAPublicKey);
	char * pEncode = new char[nLen + 1] ;
	int ret = RSA_public_encrypt(strData.length() , (const unsigned char *)strData.c_str() , (unsigned char * ) pEncode , pRSAPublicKey , RSA_PKCS1_PADDING);
	if(ret >= 0){
		strRet = std::string(pEncode , ret) ;
	}
	char * enc_output= Base64Encode(strRet.c_str(), strRet.length(), true);
	cout<<enc_output<<endl;
	string base64Ret = std::string(enc_output, strlen(enc_output)) ;
	delete[] pEncode;
	RSA_free(pRSAPublicKey);
	fclose(hPubKeyFile);
	CRYPTO_cleanup_all_ex_data();
	
	if(strRet.length() + 1 > length){
		return 0;
	}

	memset(buffer , 0 , base64Ret.length() + 1) ;
	memcpy(buffer , &base64Ret[0] ,base64Ret.length());

	return base64Ret.length() + 1;
}
int DecodeRSAKeyFile(const char * _strPemfileName , const   char * _strData , unsigned char * buffer ,  int length){
	std::string strPemFileName = _strPemfileName;
	char * dec_output = Base64Decode((char *)_strData, strlen(_strData), true);
	std::string strData =dec_output ;
	if(strPemFileName.empty() || strData.empty()){
		assert(false);
		return 0;
	}

	FILE* hPriKeyFile = NULL;
	hPriKeyFile =  fopen(strPemFileName.c_str() , "rb");
	if(hPriKeyFile == NULL){
		assert(false);
		return 0;
	}

	std::string strRet;
	RSA* pRSAPriKey = RSA_new();
	if(PEM_read_RSAPrivateKey(hPriKeyFile , &pRSAPriKey , 0 , 0) == NULL ){
		assert(false);
		return 0;
	}
	int nLen = RSA_size(pRSAPriKey);
	char * pDecode = new char[nLen + 1];
	int ret = RSA_private_decrypt(strData.length(), (const unsigned char *)strData.c_str() , (unsigned char *)pDecode , pRSAPriKey , RSA_PKCS1_PADDING);
	if(ret >= 0){
		strRet = std::string((char *)pDecode , ret);
	}

	delete [] pDecode;
	RSA_free(pRSAPriKey);
	fclose(hPriKeyFile);
	CRYPTO_cleanup_all_ex_data();
	if(strRet.length() + 1 > length){
		return 0 ;
	} else {
		memset(buffer , 0 , strRet.length() + 1);
		memcpy(buffer , &strRet[0] , strRet.length());
	}

	return strRet.length() + 1 ;

}

int main()
{
	const std::string one = "abcdeF";
	std::string strPubKey = "pubkey.pem";
	const char  *char1=strPubKey.c_str() ;
	const char  *char2=one.c_str();
	unsigned char buffer[512] , buffer1[512];
	int length = EncodeRSAKeyFile(char1 , char2 , buffer , 512);
	std::string strResult((char*)buffer,length);
	std::string strPriKey = "key.pem";
	length = DecodeRSAKeyFile(strPriKey.c_str() ,(char*)buffer, buffer1 , 512 );
	std::string strOrgTxt = std::string((char *)buffer1 , length);
	cout<<strOrgTxt<<endl;
	return 0;
}